/*            Copyright(c) 2006-2008 Dave Sexton           *
 * http://www.codeplex.com/DocProject                      *
 * http://www.codeplex.com/DocProject/Project/License.aspx *
 ***********************************************************/
using System;
using System.Collections.Generic;
using System.Text;

namespace DaveSexton.DocProject
{
	public delegate IEnumerable<T> EnumerableBuilder<T>();
	public delegate IEnumerable<T> ParameterizedEnumerableBuilder<T>(object[] arguments);

	[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
	public class MarshalByRefEnumerable<T> : MarshalByRefObject, IEnumerable<T>
	{
		#region Private / Protected
		private readonly IEnumerable<T> enumerable;
		private readonly object lifetimeService;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new instance of the <see cref="MarshalByRefEnumerable" /> class.
		/// </summary>
		public MarshalByRefEnumerable(EnumerableBuilder<T> builder)
		{
			if (builder == null)
				throw new ArgumentNullException("builder");

			enumerable = builder();

			if (enumerable == null)
				throw new InvalidOperationException("The specified builder returned a null reference.");
		}

		/// <summary>
		/// Constructs a new instance of the <see cref="MarshalByRefEnumerable" /> class.
		/// </summary>
		public MarshalByRefEnumerable(object lifetimeService, EnumerableBuilder<T> builder)
		{
			if (builder == null)
				throw new ArgumentNullException("builder");

			enumerable = builder();

			if (enumerable == null)
				throw new InvalidOperationException("The specified builder returned a null reference.");

			this.lifetimeService = lifetimeService;
		}

		/// <summary>
		/// Constructs a new instance of the <see cref="MarshalByRefEnumerable" /> class.
		/// </summary>
		public MarshalByRefEnumerable(ParameterizedEnumerableBuilder<T> builder, params object[] args)
		{
			if (builder == null)
				throw new ArgumentNullException("builder");

			enumerable = builder(args);

			if (enumerable == null)
				throw new InvalidOperationException("The specified builder returned a null reference.");
		}

		/// <summary>
		/// Constructs a new instance of the <see cref="MarshalByRefEnumerable" /> class.
		/// </summary>
		public MarshalByRefEnumerable(object lifetimeService, ParameterizedEnumerableBuilder<T> builder, params object[] args)
		{
			if (builder == null)
				throw new ArgumentNullException("builder");

			enumerable = builder(args);

			if (enumerable == null)
				throw new InvalidOperationException("The specified builder returned a null reference.");

			this.lifetimeService = lifetimeService;
		}

		/// <summary>
		/// Constructs a new instance of the <see cref="MarshalByRefEnumerable" /> class.
		/// </summary>
		public MarshalByRefEnumerable(IEnumerable<T> enumerable)
		{
			if (enumerable == null)
				throw new ArgumentNullException("enumerable");

			this.enumerable = enumerable;
		}

		/// <summary>
		/// Constructs a new instance of the <see cref="MarshalByRefEnumerable" /> class.
		/// </summary>
		public MarshalByRefEnumerable(object lifetimeService, IEnumerable<T> enumerable)
		{
			if (enumerable == null)
				throw new ArgumentNullException("enumerable");

			this.enumerable = enumerable;
			this.lifetimeService = lifetimeService;
		}

		/// <summary>
		/// Constructs a new instance of the <see cref="MarshalByRefEnumerable" /> class.
		/// </summary>
		public MarshalByRefEnumerable(params T[] items)
		{
			if (items == null)
				throw new ArgumentNullException("items");

			this.enumerable = new List<T>(items);
		}

		/// <summary>
		/// Constructs a new instance of the <see cref="MarshalByRefEnumerable" /> class.
		/// </summary>
		public MarshalByRefEnumerable(object lifetimeService, params T[] items)
		{
			if (items == null)
				throw new ArgumentNullException("items");

			this.enumerable = new List<T>(items);
			this.lifetimeService = lifetimeService;
		}
		#endregion

		#region Methods
		[System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.LinkDemand,
			Flags = System.Security.Permissions.SecurityPermissionFlag.Infrastructure)]
		public override object InitializeLifetimeService()
		{
			return lifetimeService;
		}

		public virtual IEnumerator<T> GetEnumerator()
		{
			return new MarshalByRefEnumerator<T>(lifetimeService, enumerable);
		}

		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return new MarshalByRefEnumerator<T>(lifetimeService, enumerable);
		}
		#endregion
	}
}
